/*
 * EvolutiveCaseGenerator.cpp
 *
 *  Created on: 29/05/2011
 *      Author: godinho
 */

#include <evolutive/EvolutiveCaseGenerator.h>

#include <iostream>
#include <utils.h>

EvolutiveCaseGenerator::EvolutiveCaseGenerator() {
	mRecycler = CaseRecycler::getInstance();
	mParents = std::vector<Case*>();
	mChildren = std::vector<Case*>();
	mFitnessFunction = 0;
	mLifeSimulator = 0;
	mCaseSelector = 0;
	mOffspringGenerator = 0;
	mEndIterations = false;
	mListener = 0;
	mNumIterations = -1;
}

EvolutiveCaseGenerator::~EvolutiveCaseGenerator() {
    killGeneration(mParents);
	delete mFitnessFunction;
	delete mLifeSimulator;
	delete mCaseSelector;
	delete mOffspringGenerator;
}

void EvolutiveCaseGenerator::setLocalview(localview::LocalView* lv) {
	mLocalview = lv;
}

void EvolutiveCaseGenerator::startEvolution(std::vector<Case*> cases, int phaseId) {
	mParents.clear();
	mChildren.clear();

	std::vector<Case*> aux;
	std::vector<Case*> sons;

	for(int i = 0; i < cases.size(); i++){
	    Case* c = cases[i];
		mParents.push_back(c);
	}

	int id = 0;
	int generationNum = 0;

	Case* parent1;
	Case* parent2;

    id = 0;
	while(!timedOut()) {

		//TODO include log code
		//std::cout << "Generation " << generationNum << "\n";

		if(mListener != 0) {
			mListener->newGeneration(generationNum);
		}

		//Generate sons
		for(unsigned int i = 0; i < mParents.size()/2; i++) {

			//Select parents
			parent1 = mCaseSelector->select(mParents);
			parent2 = mCaseSelector->select(mParents);

			sons = mOffspringGenerator->generate(parent1, parent2, id);

			mChildren.push_back(sons[0]);
			mChildren.push_back(sons[1]);

			id+=2;
		}

		mLifeSimulator->simulate(mChildren, mLocalview, 100, phaseId);

		for(int i = 0; i < mChildren.size(); i++) {
		    Case* c = mChildren[i];
			float fitness = mFitnessFunction->fitness(c);
			c->setFitness(fitness);
		}

		if(mListener != 0) {
		    mListener->generation(mChildren);
		}

		//Recycle parents cases
		if(generationNum > 0) {
			killGeneration(mParents);
		}

		//Children become parent, and children are cleared
		mParents = mChildren;
		mChildren = std::vector<Case*>();

		generationNum++;
	}
}

std::vector<Case*> EvolutiveCaseGenerator::getCases() {
	return mParents;
}

void EvolutiveCaseGenerator::killGeneration(std::vector<Case*> cases) {
	std::vector<Case*>::iterator it;

	for(it = cases.begin(); it != cases.end(); it++) {
		mRecycler->die(*it);
	}
}

bool EvolutiveCaseGenerator::timedOut() {
	return mEndIterations; // || (mNumIterations != -1 ? (--mNumIterations == 0) : false;
}

void EvolutiveCaseGenerator::setEventListener(EventListener* listener) {
	mListener = listener;
	mOffspringGenerator->setEventListener(listener);
}

void EvolutiveCaseGenerator::setFitnessFunction(FitnessFunction* fitnessFunction) {
	mFitnessFunction = fitnessFunction;
}

void EvolutiveCaseGenerator::setLifeSimulator(LifeSimulator* lifeSimulator) {
	mLifeSimulator = lifeSimulator;
}

void EvolutiveCaseGenerator::setCaseSelector(CaseSelector* selector) {
	mCaseSelector = selector;
}

void EvolutiveCaseGenerator::setOffspringGenerator(OffspringGenerator* offspringGenerator) {
	mOffspringGenerator = offspringGenerator;
}

FitnessFunction* EvolutiveCaseGenerator::getFitnessFunction() {
	return mFitnessFunction;
}

LifeSimulator* EvolutiveCaseGenerator::getLifeSimulator() {
	return mLifeSimulator;
}

CaseSelector* EvolutiveCaseGenerator::getCaseSelector() {
	return mCaseSelector;
}

OffspringGenerator* EvolutiveCaseGenerator::getOffspringGenerator() {
	return mOffspringGenerator;
}

void EvolutiveCaseGenerator::setNumInterations(int num) {
    mNumIterations = num;
}

void EvolutiveCaseGenerator::setTimedOut() {
	mEndIterations = true;
	mLifeSimulator->stopSimulation();
}
